home *** CD-ROM | disk | FTP | other *** search
- #include <c.h>
- #include <fcntl.h>
- #include <libc.h>
- #include <netdb.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <utmp.h>
-
- #include <arpa/inet.h>
-
- #include <netinet/in.h>
-
- #include <sys/param.h>
- #include <sys/stat.h>
- #include <sys/socket.h>
- #include <sys/time.h>
- #include <sys/types.h>
-
- #import "UDPLoadView.h"
- #import "NLoadCommon.h"
-
- @implementation UDPLoadView
-
- /*---------------------------------------------------------------------------
- Besides creating the new frame, initialize variables to default settings.
- With the addition of the RPC/UDP support, some new variables were added.
- These variables, initial settings, and impact of the settings follow:
-
- Initial
- Variable Setting Comment
- hostName NULL overridden later to host name,
- nErrors MAX... forces the view white if the first client/server
- call fails; then records # consecutive errors,
- turning the view white after MAXERRORS,
- udpSocket -1 forces initial udpClient call to create socket,
- waitSeconds WS.. default seconds to wait on remote server
- (can be overridden by defaults data base)
- -----------------------------------------------------------------------------*/
-
- - initFrame:(const NXRect *) frameRect
- {
- const char *string;
-
- waitSecs = WAITSECONDS;
-
- if ((string = getDefault("HostsWaitSeconds")) && sscanf(string, "%d", &waitSecs) != 1)
- waitSecs = WAITSECONDS;
-
- udpSocket = -1;
-
- return [super initFrame:frameRect];
- }
-
- - startTimer
- {
- const char *string;
- int time = REMOTEUPDATE;
-
- if ((string = getDefault("RemoteUpdateSeconds")) && sscanf(string, "%d", &time) != 1)
- time = REMOTEUPDATE;
-
- timedEntry = DPSAddTimedEntry((double) time, (DPSTimedEntryProc) &timer, self, NX_BASETHRESHOLD);
-
- return self;
- }
-
- /*---------------------------------------------------------------------------
- This code is used for remote hosts that do not have RPC support. A dedicated
- load server must run on the remote hosts. Most sites will never execute this
- code.
-
- If we do not have a UDP socket upon entry, we must go through the laborious
- task of setting one up. This requires that we create the socket, set it
- up for no delay, and bind it.
-
- Once we have a valid UDP socket, we send a tickler UDP packet to the remote
- host. We wait a short period of time for the remote host to respond. We
- expect the server to reply with a string of the form:
- "hostname load1 load5 load15 scale"
- -----------------------------------------------------------------------------*/
- - loadAverage:(long *)vector loadScale:(int *)scale
- {
- char buf[BUFSIZ];
- char *bufPtr;
-
- int i;
- int nBytes;
- int newSocket;
- int temp;
-
- struct sockaddr_in clientSocket;
- struct hostent *hp;
-
- if (udpSocket < 0) {
- if ((hp = gethostbyname((char *) hostName)) == NULL) {
- fprintf(stderr, "Unknown host '%s'.\n", hostName);
- return nil;
- }
-
- /* Set up the UDP server socket.
- * Client and server both use UDPSERVERPORT.
- */
- bzero((char *) &udpServerSocket, sizeof(udpServerSocket));
- udpServerSocket.sin_family = AF_INET;
-
- bcopy(hp->h_addr, &udpServerSocket.sin_addr.s_addr, hp->h_length);
- udpServerSocket.sin_port = htons(UDPSERVERPORT);
-
- /* Create the client's socket. Set this socket for no delay so
- * we can time out if the server is down or slow in responding.
- * Bind the socket to appropriate protocol, host, and port.
- */
- if ((newSocket = socket(AF_INET, SOCK_DGRAM, 0)) == CERROR) {
- fprintf (stderr,"Can not open datagram socket.\n");
- return nil;
- }
-
- if (fcntl(newSocket, F_SETFL, FNDELAY) == CERROR) {
- fprintf(stderr, "fcntl F_SETFL, FNDELAY error.\n");
- close(newSocket);
- return nil;
- }
-
- bzero((char *) &clientSocket, sizeof(clientSocket)); /* zero out */
- clientSocket.sin_family = AF_INET;
- clientSocket.sin_addr.s_addr = htonl(INADDR_ANY);
- clientSocket.sin_port = htons(0);
-
- if (bind(newSocket, (struct sockaddr *) &clientSocket, sizeof(clientSocket)) == CERROR) {
- fprintf (stderr, "Unable to bind the local address.\n");
- close (newSocket);
- return nil;
- }
-
- udpSocket = newSocket; /* Success. Finalize the deal! */
- }
-
- /* Send a tickler character to the remote server to wake it up. The
- * server should return a string with the host name, load values, and
- * scale value.
- */
- if (sendto(udpSocket, "T", 1, 0, (struct sockaddr *) &udpServerSocket, sizeof(udpServerSocket)) == CERROR) {
- close (udpSocket);
- udpSocket = -1; /* Forces initialization at next entry. */
- return nil;
- }
-
- /* Patiently wait "waitSecs" seconds for the remote server to respond. We
- * throw away any packets we receive from servers that we don't expect to
- * hear from.
- */
- nBytes = 0;
- for (i = 0; i < waitSecs && nBytes <= 0 ; i++) {
- sleep (1);
-
- nBytes = recvfrom(udpSocket, buf, BUFSIZ-1, 0, NULL, &temp);
-
- if (nBytes > 0 && strncmp (hostName, buf, strlen(hostName)) != 0) nBytes = 0;
- }
-
- if (nBytes <= 0) {
- close(udpSocket);
- udpSocket = -1; /* Forces initialization at next entry. */
- return nil;
- }
-
- /* At this point we have a response from the server. The server should
- * have returned a string in the form "hostname load1 load5 load15 scale".
- * Extract the values and return.
- */
- buf[nBytes] = '\0';
-
- bufPtr = strtok (buf, " ");
- bufPtr = strtok (NULL, " "); /* Skip the slave's host name */
-
- for (i = 0; i < QUEUES; i++) {
- if (bufPtr == NULL) break;
-
- vector[i] = atoi(bufPtr);
- bufPtr = strtok (NULL, " ");
- }
-
- if (bufPtr == NULL) return nil;
-
- *scale = atoi (bufPtr);
- return self;
- }
-
- @end
-